iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
Modern Web

淺入淺出 Rails with Vue系列 第 19

【Day 19】淺入淺出 Rails with Vue - Vue 的基本概念 - 18

  • 分享至 

  • xImage
  •  

前言

本系列將介紹 Rails with Vue 的基本概念,並且以一個簡單的專案 Todo 來說明如何使用 Rails with Vue。我將透過這一系列的文章記錄我學習的過程,並且將我所學到的知識分享給大家。

Components Basics

A Single Root Element

當我們建立 <blog-post> 時,component 的 template 一定不只有 title 這麼單純,

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

至少,還會有 content

<h3>{{ title }}</h3>
<div v-html="content"></div>

但假如我們這麼做的話,Vue 會報錯,並且解釋 every component must have a single root element,也就是說,每個 component 都必須有一個單一的 root element。
這時候,我們可以使用 <div> 包起來,讓它變成一個單一的 root element (div)。

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

而隨著 component 漸漸長大,我們可能不只需要 title 和 content,還需要其他的東西,像是 publishedAt、comments 等等,
這時候如果每個都透過定義一個 prop 來傳遞,那麼會變得很麻煩,
如以下範例中,我們需要傳遞 title、content、publishedAt、comments 這 4 個 prop

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"
  v-bind:content="post.content"
  v-bind:publishedAt="post.publishedAt"
  v-bind:comments="post.comments"
></blog-post>

為了解決這個問題,我們可以使用 v-bind 來傳遞一個單一物件 prop 來解決。
如以下範例中,我們使用 v-bind:post="post" 來傳遞一個物件 post prop,這個 prop 包含了 title、content 這 2 個資料。


```html
<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:post="post"
></blog-post>
Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})

以上範例中我們使用了 JavaScript’s template literal 來達成多行 template 並增加可讀性,但這樣的方法在 IE 中不支援,如果你需要支援 IE,可以使用 newline escapes 來達成多行 template。

Listening to Child Components Events

隨著 component 的漸漸長大,我們可能會需要在 component 中觸發一些事件,並且在 parent component 中監聽這些事件,並且執行一些動作。
例如我們希望新增一個 accessibility feature 功能來讓使用者可以可以將文章的內容放大檢視。
在 parent 中,我們可以新增一個 postFontSize 的 data 用來支援這個功能。

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

接著我們可以用這個 postFontSize 的 data 來控制 blog-post component 的樣式。

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

在 component 中,我們可以新增一個 button 來讓使用者可以點擊來放大文章內容。

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

想當然爾,只把 button 加上去當然不會動,會動很可怕,
我們希望當使用者點擊 Enlarge text 按鈕時,可以觸發一個事件,並且在 parent 中監聽這個事件,並且執行一些動作。
幸運的是,Vue instance 提供了一個 custom system event 來支援這個功能。
parent (new Vue()) 可以使用 v-on 來監聽任何來自 child component 的事件。
例如以下範例中,我們監聽 enlarge-text 事件,並且在觸發時,將 postFontSize 的值增加 0.1。

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"
></blog-post>

接著 child component 可以使用 this.$emit 來觸發一個事件,讓 parent component 可以監聽到。
使用的方法就是 this.$emit('event-name'),例如以下範例中,我們在 Enlarge text 按鈕的 click event 中觸發 enlarge-text 事件。

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button>

當 child component 發射 enlarge-text 事件時,parent component 就會接收到並且執行 postFontSize += 0.1 這個動作,真 ㄅㄧㄤˋ。

Reference


上一篇
【Day 18】淺入淺出 Rails with Vue - Vue 的基本概念 - 17
下一篇
【Day 20】淺入淺出 Rails with Vue - Vue 的基本概念 - 19
系列文
淺入淺出 Rails with Vue30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言